package com.gitee.elf.core.entity.event

import com.gitee.elf.core.entity.EntityInstance
import com.gitee.elf.core.entity.EntityTheme
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import taboolib.common.LifeCycle
import taboolib.common.io.getInstance
import taboolib.common.io.runningClasses
import taboolib.common.platform.Awake
import taboolib.common.platform.function.adaptPlayer
import taboolib.common.platform.function.console
import taboolib.common5.Baffle
import taboolib.module.kether.KetherShell
import taboolib.module.kether.ScriptContext
import taboolib.module.kether.runKether
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit

object EntityEventManager {

    val events = mutableMapOf<String, EntityEvent>()

    fun getEvent(id: String) = events[id]

    val baffles = mutableMapOf<EntityTheme.EventHandler, Baffle>()

    @Awake(LifeCycle.LOAD)
    fun load() {
        runningClasses.forEach {
            if (EntityEvent::class.java.isAssignableFrom(it)) {
                val event = it.getInstance()?.get() as? EntityEvent ?: return@forEach
                events[event.id] = event
            }
        }
    }

    fun EntityInstance.invokeScript(event: EntityEvent, block: ScriptContext.() -> Unit = {}) {
        val handlers = theme?.events?.filter { it.bind == event.id } ?: return
        handlers.forEach { invokeScript(it, block) }
    }

    fun EntityInstance.invokeScript(handler: EntityTheme.EventHandler, block: ScriptContext.() -> Unit = {}): CompletableFuture<Any?>? {
        // 阻断器
        if (!baffles.computeIfAbsent(handler) { Baffle.of(handler.baffle, TimeUnit.MILLISECONDS) }.hasNext(this.id.toString())) {
            return null
        }
        return invokeScript(handler.action, this.owner) {
            this.rootFrame().variables()["@EntityInstance"] = this
            block(this)
        }
    }

    private fun invokeScript(action: String, sender: Entity, block: ScriptContext.() -> Unit = {}): CompletableFuture<Any?>? {
        return runKether {
            KetherShell.eval(action, namespace = listOf("elf-entity")) {
                this.sender = if (sender is Player) {
                    adaptPlayer(sender)
                } else {
                    console()
                }
                block(this)
            }
        }
    }

}